﻿using System;
using System.Data;
using System.Data.Common;
using System.Data.Objects;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ExtensionMethods
{
    public static class Visualizer
    {
        public static void VisualizeObjectStateEntry(this EntityKey eKey, ObjectContext context)
        {
            ObjectStateEntry ose = null;
            //If object is Detached, then there will be no Entry in the ObjectStateManager
            //new entities that are not attached will not even have an entitykey
            if (eKey == null || !(context.ObjectStateManager.TryGetObjectStateEntry(eKey, out ose)))
                MessageBox.Show("Object is not currently being change tracked and no ObjectStateEntry exists.", "ObjectStateEntryVisualizer", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            else
            {
                var currentValues = ose.CurrentValues;
                //If Object is Added, there will be no Original values and it will throw an exception
                DbDataRecord originalValues = null;
                if (ose.State != EntityState.Added)
                    originalValues = ose.OriginalValues;

                //walk through arrays to get the values
                var valueArray = new System.Collections.ArrayList();
                for (var i = 0; i < currentValues.FieldCount; i++)
                {
                    //metadata provides field names
                    var sName = currentValues.DataRecordInfo.FieldMetadata[i].FieldType.Name;
                    bool isdbDataRecord = false;
                    var sCurrVal = currentValues[i];
                    object sOrigVal = null;

                    //test for complex type
                    if (currentValues[i] is DbDataRecord)
                        isdbDataRecord = true;

                    if (isdbDataRecord == false) //normal scalar data
                        sCurrVal = currentValues[i];
                    else //complex type, anything else?
                        sCurrVal = ComplexTypeString((DbDataRecord)currentValues[i]);

                    if (ose.State == EntityState.Added)
                        sOrigVal = "n/a"; //this will be for Added entities
                    else
                    {
                        if (isdbDataRecord == false) //normal scalar data
                            sOrigVal = originalValues[i];
                        else //complex type
                            sOrigVal = ComplexTypeString((DbDataRecord)originalValues[i]);
                    }
                    string changedProp = (
                            from prop in ose.GetModifiedProperties()
                            where prop == sName
                            select prop).FirstOrDefault();

                    string propModified;

                    if (changedProp == null)
                        propModified = "";
                    else
                        propModified = "X";
                    valueArray.Add(new { _Index = i.ToString(), _Property = sName, Current = sCurrVal, Original = sOrigVal, ValueModified = propModified });
                }

                //FormMainEFDebugger frm = new FormMainEFDebugger();
                //frm.Init(valueArray, ose.State.ToString(), ose.Entity.ToString());
                //frm.ShowDialog();
            }
        }

        private static string ComplexTypeString(DbDataRecord item)
        {
            var dbRecString = new StringBuilder();
            for (var i = 0; i < item.FieldCount; i++)
            {
                if (item[i] == DBNull.Value)
                    dbRecString.AppendLine();
                else
                    dbRecString.AppendLine((String)(item[i]));
            }
            return dbRecString.ToString();
        }
    }
}